package com.kangyi.user.service.Impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.kangyi.constant.MessageConstant;
import com.kangyi.dto.FavoriteDTO;
import com.kangyi.dto.NursingHomeDetailDTO;
import com.kangyi.dto.NursingHomeFilterDTO;
import com.kangyi.dto.NursingHomePageQueryDTO;
import com.kangyi.entity.*;
import com.kangyi.exception.DataNotExistException;
import com.kangyi.result.PageResult;
import com.kangyi.user.mapper.*;
import com.kangyi.user.service.NursingHomeServices;
import com.kangyi.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Blank
 * @version 1.0
 */
@Service
@Slf4j
public class NursingHomeServiceImpl implements NursingHomeServices {

    @Autowired
    private NursingHomeMapper nursingHomeMapper;

    @Autowired
    private NursingHomeTagMapper nursingHomeTagMapper;

    @Autowired
    private NursingHomeRequirementMapper nursingHomeRequirementMapper;

    @Autowired
    private FeeMapper feeMapper;

    @Autowired
    private NursingHomeServiceMapper nursingHomeServiceMapper;

    @Autowired
    private NursingHomeEventMapper nursingHomeEventMapper;

    @Autowired
    private NursingHomeReviewMapper nursingHomeReviewMapper;

    @Autowired
    private NursingHomeReviewImageMapper nursingHomeReviewImageMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private NursingHomeFavoriteMapper nursingHomeFavoriteMapper;

    // 封装获取养老院标签的方法，提高代码复用性
    private Map<Integer, List<NursingHomeTagVO>> getNursingHomeTagsMap(List<Integer> nursingHomeIds) {
        List<NursingHomeTagVO> nursingHomeTagVOs = nursingHomeTagMapper.getTagsByNursingHomeIds(nursingHomeIds);
        return nursingHomeTagVOs.stream()
                .collect(Collectors.groupingBy(NursingHomeTagVO::getNursingHomeId));
    }

    @Override
    public NursingHomeDetailVO inquiryNursingHomeById(NursingHomeDetailDTO nursingHomeDetailDTO) {
        Integer id = nursingHomeDetailDTO.getNursingHomeId();

        // 1. 查询养老院基本信息（包含数据库计算好的评分）
        NursingHomeDetailVO nursingHomeDetailVO = nursingHomeMapper.getNursingHomeById(id);
        if (nursingHomeDetailVO == null) {
            throw new DataNotExistException("养老院不存在");
        }

        List<Integer> nursingHomeIds = Collections.singletonList(id);

        // 2. 查询养老院标签
        Map<Integer, List<NursingHomeTagVO>> tagMap = getNursingHomeTagsMap(nursingHomeIds);
        nursingHomeDetailVO.setNursingHomeTagVOList(tagMap.getOrDefault(id, new ArrayList<>()));

        // 3. 查询养老院收费信息
        List<FeeVO> feeVOList = feeMapper.inquiryNursingHomeFees(id);
        nursingHomeDetailVO.setFeeVOList(feeVOList);

        // 4. 查询养老院特色服务
        List<NursingHomeServiceVO> serviceVOList = nursingHomeServiceMapper.inquiryNursingHomeServices(id);
        nursingHomeDetailVO.setNursingHomeServiceVOList(serviceVOList);

        // 5. 查询养老院精彩活动
        List<NursingHomeEventVO> eventList = nursingHomeEventMapper.inquiryNursingHomeEvents(id);
        nursingHomeDetailVO.setNursingHomeEventVOList(eventList);

        // 6. 查询养老院评论
        List<NursingHomeReviewVO> reviewList = nursingHomeReviewMapper.inquiryNursingHomeReviews(id);
        nursingHomeDetailVO.setNursingHomeReviewVOList(reviewList);
        nursingHomeDetailVO.setTotalReview(reviewList.size()); // 设置评论总条数

        if (!reviewList.isEmpty()) {
            // 6.1 收集所有评论 ID
            List<Integer> reviewIds = reviewList.stream()
                    .map(NursingHomeReviewVO::getId)
                    .collect(Collectors.toList());

            // 6.2 批量查询所有评论的图片，并按 sort 排序
            List<NursingHomeReviewImageVO> nursingHomeReviewImageVOList = nursingHomeReviewImageMapper
                    .getImgsByReviewIdsSorted(reviewIds);

            // 6.3 按评论 ID 分组映射
            Map<Integer, List<NursingHomeReviewImageVO>> reviewImageVOMap = nursingHomeReviewImageVOList.stream()
                    .collect(Collectors.groupingBy(NursingHomeReviewImageVO::getNursingHomeReviewId));

            // 6.4 赋值图片列表到相应评论
            for (NursingHomeReviewVO reviewVO : reviewList) {
                reviewVO.setNursingHomeReviewImageVOList(reviewImageVOMap.getOrDefault(reviewVO.getId(), new ArrayList<>()));
            }

            // 6.5 收集所有评论的用户 ID
            List<Integer> userIds = reviewList.stream()
                    .map(NursingHomeReviewVO::getCreateUser)
                    .distinct()
                    .collect(Collectors.toList());

            if (!userIds.isEmpty()) {
                // 6.6 批量查询用户信息
                List<UserVO> userList = userMapper.getUsersByIds(userIds);

                // 6.7 转换为 Map，方便快速查找
                Map<Integer, UserVO> userMap = userList.stream()
                        .collect(Collectors.toMap(UserVO::getId, user -> user));

                // 6.8 赋值用户数据到评论，并隐藏手机号后 6 位
                for (NursingHomeReviewVO reviewVO : reviewList) {
                    UserVO userVO = userMap.get(reviewVO.getCreateUser());
                    if (userVO != null) {
                        // 处理手机号隐藏后 6 位
                        if (userVO.getPhone() != null && userVO.getPhone().length() >= 6) {
                            String phone = userVO.getPhone();
                            userVO.setPhone(phone.substring(0, phone.length() - 6) + "******");
                        }
                        reviewVO.setUserVO(userVO);
                    }
                }
            }
        }

        // 9. 查询入住条件
        List<NursingHomeRequirementVO> requirementVOList = nursingHomeRequirementMapper.inquiryNursingHomeRequirements(id);
        nursingHomeDetailVO.setNursingHomeRequirementVOList(requirementVOList);

        // 当前用户id
        Integer userId = nursingHomeDetailDTO.getUserId();
        FavoriteDTO build = FavoriteDTO.builder()
                .nursingHomeId(id)
                .userId(userId).build();
        NursingHomeFavorite nursingHomeFavorite = nursingHomeFavoriteMapper.selectByUserIdAndNursingHomeId(build);
        nursingHomeDetailVO.setCollect(nursingHomeFavorite != null);

        return nursingHomeDetailVO;
    }




    @Override
    public List<NursingHomeHotVO> HotNursingHome(BigDecimal rating) {
        // 首先创建一个ArrayList实体类，用于存储最终要返回的热门养老院列表
        List<NursingHomeHotVO> resultList = new ArrayList<>();
        // 我们使用Mapper层调用数据库，
        // 查询传rating参数获取养老院列表，并将其赋值给list集合
        List<NursingHomeHotVO> highRateNursingHomes = nursingHomeMapper.getTopRatedNursingHomes(rating);
        // 创建一个HashSet集合，用于存储已被选中的养老院的ID，确保不会重复添加
        Set<Integer> selectedIds = new HashSet<>();
        // 遍历高评分的养老院列表
        for (NursingHomeHotVO home : highRateNursingHomes) {
            // 判断resultList中的元素数量是否小于3，并且当前养老院的ID不在selectedIds集合中
            if (resultList.size() < 3 && !selectedIds.contains(home.getId())) {
                // 如果满足条件，将该养老院添加到resultList集合中
                resultList.add(home);
                // 同时将该养老院的ID添加到selectedIds集合中，避免后续重复添加
                selectedIds.add(home.getId());
            }
        }

        // 当resultList集合中的元素数量小于3时，进入循环尝试补充更多的养老院
        while (resultList.size() < 3) {
            // 调用Mapper的查询方法，
            // 获取除了已经选中的养老院之外的最新热门养老院列表，
            // 并根据还需要补充的数量进行查询，并将其赋值给list集合
            List<NursingHomeHotVO> newestHomes = nursingHomeMapper.getNewestHotNursingHomes(new ArrayList<>(selectedIds), 3 - resultList.size());
            //
            for (NursingHomeHotVO home : newestHomes) {
                // 判断resultList中的元素数量是否小于3，并且当前养老院的ID不在selectedIds集合中
                if (resultList.size() < 3 && !selectedIds.contains(home.getId())) {
                    // 如果满足条件，将该养老院添加到resultList中
                    resultList.add(home);
                    // 同时将该养老院的ID添加到selectedIds集合中，避免后续重复添加
                    selectedIds.add(home.getId());
                }
            }
            // 如果最新热门养老院列表为空，说明没有更多符合条件的养老院了，跳出循环
            if (newestHomes.isEmpty()) break;
        }
        // 如果经过上述操作后，resultList集合中的元素数量仍然小于3，说明没有找到足够的养老院符合条件
        if (resultList.size() < 3) {
            // 抛出异常，并给出相应的提示信息
            throw new DataNotExistException("没有找到足够的养老院符合条件");
        }
        // 使用Stream流将resultList集合中每个养老院的ID提取出来，存储到nursingHomeIds列表中
        List<Integer> nursingHomeIds = resultList.stream()
                .map(NursingHomeHotVO::getId)
                .collect(Collectors.toList());

        // 调用getNursingHomeTagsMap方法，根据nursingHomeIds列表获取每个养老院对应的标签列表，
        // 存储在tagMap中，键为养老院ID，值为对应的标签列表
        Map<Integer, List<NursingHomeTagVO>> tagMap = getNursingHomeTagsMap(nursingHomeIds);

        // 遍历resultList中的每个养老院
        for (NursingHomeHotVO nursingHome : resultList) {
            // 从tagMap中获取该养老院对应的标签列表，如果不存在则返回一个空列表，
            // 并将其设置到该养老院对象的nursingHomeTagVOList属性中
            nursingHome.setNursingHomeTagVOList(tagMap.getOrDefault(nursingHome.getId(), new ArrayList<>()));
        }
        //我们将resultList 这个实体类return返回出去
        return resultList;
    }
    @Override
    public List<NursingHomeRecommendVO> NursingHomeRecommend(NursingHomeFilterDTO filter) {

        List<NursingHomeRecommendVO> nursingHomeList = nursingHomeMapper.getRecommendedNursingHomes(filter);

        // 使用 TreeSet 避免键冲突，以价格低的优先排序
        // 修改比较器，当价格相同时比较 id，避免意外去重
        TreeSet<NursingHomeRecommendVO> nursingHomeTreeSet = new TreeSet<>((o1, o2) -> {
            BigDecimal fee1 = o1.getLowRoomFee() != null ? o1.getLowRoomFee() : BigDecimal.ZERO;
            BigDecimal fee2 = o2.getLowRoomFee() != null ? o2.getLowRoomFee() : BigDecimal.ZERO;
            int feeComparison = fee1.compareTo(fee2);
            if (feeComparison != 0) {
                return feeComparison;
            }
            // 如果价格相同，比较 id
            return o1.getId().compareTo(o2.getId());
        });
        nursingHomeTreeSet.addAll(nursingHomeList);

        // 如果用户没有传入任何值且数量不足 3 条，执行补充查询
        if (nursingHomeTreeSet.size() < 3) {
            List<Integer> existingIds = nursingHomeList.stream()
                    .map(NursingHomeRecommendVO::getId)
                    .collect(Collectors.toList());

            int remainingCount = 3 - nursingHomeTreeSet.size();

            List<NursingHomeRecommendVO> additionalNursingHomes = nursingHomeMapper.getNewestNursingHomes(existingIds, remainingCount);
            nursingHomeTreeSet.addAll(additionalNursingHomes);
        }

        if (nursingHomeTreeSet.size() < 3) {
            throw new DataNotExistException("没有找到足够的养老院符合条件");
        }

        // 选取前 3 条记录
        List<NursingHomeRecommendVO> finalNursingHomeList = new ArrayList<>();
        Iterator<NursingHomeRecommendVO> iterator = nursingHomeTreeSet.iterator();
        int count = 0;
        while (iterator.hasNext() && count < 3) {
            finalNursingHomeList.add(iterator.next());
            count++;
        }

        // 获取养老院标签
        List<Integer> nursingHomeIds = finalNursingHomeList.stream()
                .map(NursingHomeRecommendVO::getId)
                .collect(Collectors.toList());

        Map<Integer, List<NursingHomeTagVO>> tagMap = getNursingHomeTagsMap(nursingHomeIds);

        // 为每个养老院设置标签
        for (NursingHomeRecommendVO nursingHome : finalNursingHomeList) {
            nursingHome.setNursingHomeTagVOList(tagMap.getOrDefault(nursingHome.getId(), new ArrayList<>()));
        }

        return finalNursingHomeList;
    }

    @Override
    public PageResult pageQuery(NursingHomePageQueryDTO nursingHomePageQueryDTO) {
        PageHelper.startPage(nursingHomePageQueryDTO.getPage(), nursingHomePageQueryDTO.getPageSize());
        Page<NursingHomeListFavoriteVO> page = nursingHomeMapper.pageQuery(nursingHomePageQueryDTO);
        long total = page.getTotal();
        List<NursingHomeListFavoriteVO> result = page.getResult();

        // 处理每个养老院的标签数据
        for (NursingHomeListFavoriteVO nursingHome : result) {
            List<NursingHomeTagVO> tags = nursingHomeTagMapper.getTagsByNursingHomeId(nursingHome.getId());
            nursingHome.setNursingHomeTagVOList(tags);
        }

        return new PageResult(total, result);
    }



}